package up7.utils;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.Key;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.fileupload.FileItem;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import up7.model.FileInf;

/**
 * 
 * @author zysoft
 * 用法：
 *
 */
public class CryptoTool
{
	private String key = "2C4ED1CC9BAA42A9";
	private String iv = "2C4ED1CC9BAA42A9";
	 //算法名称
	private String KEY_ALGORITHM = "AES";
	 //加密算法，填充方式
	 private String algorithm = "AES/CBC/NoPadding";
	
	public CryptoTool()
	{		
	}	
	 
	public String encrypt(String data) throws Exception 
	{
	    try 
	    {
	        Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
	        int blockSize = cipher.getBlockSize();

	        //ZeroPadding
	        byte[] dataBytes = data.getBytes();
	        int plaintextLength = dataBytes.length;
	        if (plaintextLength % blockSize != 0) {
	            plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
	        }
	        
	        byte[] plaintext = new byte[plaintextLength];
	        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
	        
	        SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
	        IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
	
	        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
	        byte[] encrypted = cipher.doFinal(plaintext);
	
	        return new sun.misc.BASE64Encoder().encode(encrypted);
	
	    } catch (Exception e) {
	        e.printStackTrace();
	        return null;
	    }
	}

    public String decrypt(String data) throws Exception 
    {
        try
        {	            
            byte[] encrypted1 = new BASE64Decoder().decodeBuffer(data);
            
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
            
            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
 
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original);
            return originalString;
        }
        catch (Exception e) 
        {
            e.printStackTrace();
            return null;
        }
    }
	/**
	 * aes/cbc/pkcs
	 * @param s  加密后的数据(16byte对齐)
	 * @return
	 */
	private ByteArrayOutputStream aes_decode(ByteArrayOutputStream s) {

		try
		{
			byte[] buf = s.toByteArray();
			String ago="AES/CBC/PKCS5Padding";
			this.KEY_ALGORITHM="AES";

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(ago, BouncyCastleProvider.PROVIDER_NAME);
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] out = cipher.doFinal(buf);
			ByteArrayOutputStream ost = new ByteArrayOutputStream();
			ost.write(out,0,out.length);
			return ost;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * SM4/ECB/PKCS5Padding
	 * @param s
	 * @return
	 */
	private ByteArrayOutputStream sm4_decode(ByteArrayOutputStream s)
	{
		try
		{
			byte[] buf = s.toByteArray();
			String ago="SM4/CBC/PKCS5Padding";
			this.KEY_ALGORITHM="SM4";

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(ago, BouncyCastleProvider.PROVIDER_NAME);
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] out = cipher.doFinal(buf);
			ByteArrayOutputStream ost = new ByteArrayOutputStream();
			ost.write(out,0,out.length);
			return ost;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	public ByteArrayOutputStream decrypt(String aligo, ByteArrayOutputStream block)
	{
		if(aligo.equalsIgnoreCase("sm4")) return this.sm4_decode(block);
		return this.aes_decode(block);
	}

	public String encrypt(byte[] dataBytes) throws Exception
	{
		try
		{
			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
			int blockSize = cipher.getBlockSize();

			//ZeroPadding
			//byte[] dataBytes = data.getBytes();
			int plaintextLength = dataBytes.length;
			if (plaintextLength % blockSize != 0) {
				plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
			}

			byte[] plaintext = new byte[plaintextLength];
			System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
			byte[] encrypted = cipher.doFinal(plaintext);

			return new sun.misc.BASE64Encoder().encode(encrypted);

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public String decrypt(String data, String encode) throws Exception
	{
		try
		{
			byte[] encrypted1 = new BASE64Decoder().decodeBuffer(data);

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] original = cipher.doFinal(encrypted1);
			String originalString = new String(original,encode);
			return originalString.trim();
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	public byte[] encrypt(FileItem data) throws Exception
	{
		try
		{
			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
			int blockSize = cipher.getBlockSize();

			InputStream stm = data.getInputStream();
			byte[] dataBytes = new byte[(int)data.getSize()];
			stm.read(dataBytes);
			stm.close();
			//ZeroPadding
			//byte[] dataBytes = data.getInputStream().
			int plaintextLength = dataBytes.length;
			if (plaintextLength % blockSize != 0) {
				plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
			}

			byte[] plaintext = new byte[plaintextLength];
			System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);

			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
			byte[] encrypted = cipher.doFinal(plaintext);
			return encrypted;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public ByteArrayOutputStream decrypt(FileItem block,int lenOri) throws Exception
	{
		try
		{
			InputStream stm = block.getInputStream();
			byte[] dataBytes = new byte[(int)block.getSize()];
			stm.read(dataBytes);
			stm.close();

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
			SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
			IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

			cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

			byte[] out = cipher.doFinal(dataBytes);
			ByteArrayOutputStream ost = new ByteArrayOutputStream();
			ost.write(out,0,lenOri);
			return ost;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	public ByteArrayOutputStream decrypt(String aligo, ByteArrayOutputStream block, int len)
    {
        try {
        	if(aligo.equalsIgnoreCase("sm4")) return this.sm4_decode(block, len);
            return this.aes_decode(block, len);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
    }
	
	/**
	 * 解密数据
	 * @param block  加密后的数据(16byte对齐)
	 * @param lenOri 原始大小
	 * @return
	 * @throws Exception
	 */
	private ByteArrayOutputStream aes_decode(ByteArrayOutputStream block, int lenOri) throws Exception
	{
		try
		{
			byte[] buf = block.toByteArray();

			Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
			Cipher cipher = Cipher.getInstance(this.algorithm,BouncyCastleProvider.PROVIDER_NAME);
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

            byte[] out = cipher.doFinal(buf);
            ByteArrayOutputStream ost = new ByteArrayOutputStream();
            ost.write(out,0,lenOri);
            return ost;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return null;
        }
	}

	/**
     * SM4/ECB/PKCS5Padding
     * @param stm
     * @param lenOri
     * @return
     */
	public ByteArrayOutputStream sm4_encode(ByteArrayOutputStream stm, int lenOri)
    {
		try
        {
            byte[] buf = stm.toByteArray();

            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance(this.algorithm,"BC");
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

            byte[] out = cipher.doFinal(buf);
            ByteArrayOutputStream ost = new ByteArrayOutputStream();
            ost.write(out,0,lenOri);
            return ost;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }

	/**
     * SM4/ECB/PKCS5Padding
     * @param s
     * @param lenOri
     * @return
     */
    private ByteArrayOutputStream sm4_decode(ByteArrayOutputStream s, int lenOri)
    {

    	try
        {
            byte[] buf = s.toByteArray();
            String ago="SM4/ECB/PKCS5Padding";
            this.KEY_ALGORITHM="SM4";

            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance(ago,BouncyCastleProvider.PROVIDER_NAME);
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), this.KEY_ALGORITHM);
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());

            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);

            byte[] out = cipher.doFinal(buf);
            ByteArrayOutputStream ost = new ByteArrayOutputStream();
            ost.write(out,0,lenOri);
            return ost;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return null;
        }
    }
	
	public String token(FileInf f, String action)
	{
		String str = f.id + f.nameLoc + action;
		if(action == "block") str = f.id + f.pathSvr + action;
		str = Md5Tool.getMD5(str);
		try {
			str = this.encrypt(str);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return str;
	}

}